#include "dumpbin.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#define CHAR_PER_LINE 16
static void TraceALine(char * p, int length, int width , FILE * file)
{
	int i = 0, j = 0;

    if(length > width)
        return;

    for(j = 0; j < length; j++) {
        unsigned char x = p[j];
        fprintf(file, "%02X ", x);
    }
    for(i = 0; i < width - length; i++) {
        fprintf(file, "   ");
    }
    fprintf(file, "      ");
    for(j = 0; j < length; j++) {
        unsigned char x = p[j];
        if(x >= 32 && x <= 128/*isascii(x)*/) {
                fprintf(file, "%c", x);
        } else {
            fprintf(file, ".");
        }
    }
}

void PrintHead(int width, FILE * out)
{
	int i;

    printf("\n");
    fprintf(out, "       ");

    for(i = 0; i < width; i++) {
        printf("%2X ", i);
    }
    printf("\n");
    fprintf(out, "       ");
    for(i = 0; i < width; i++) {
        printf("-- ");
    }
    printf("\n");
}

void TraceMsg(int width, FILE * in, FILE * out/* = stdout*/)
{
    int buff[1024] = {0};
    int max_read_len;
    int iline;

    if( width < 0 ) {
        width = 16;
    }
    if( width > 0xFF) {
        width = 0xFF;
    }
    
    max_read_len = 1024/width*width;
    iline = 0;
    PrintHead(width, out);
    while(!feof(in)) {
		int i;
		char * p;
		int start;
		int length = (int)fread(buff, 1, max_read_len, in);
        if( length <= 0 ) {
            continue;
        }
        p = (char*)buff;

        for(i = 0; (length-i) >= width; i+=width) {
            fprintf(out, "%4d : ", iline++);
            TraceALine(&p[i], width, width, out);
            fprintf(out, "\n");
        }
        //the rest
        start = length/width * width;
        if( start >= length ) {
            continue;
        }
        fprintf(out, "%4d : ", iline++);
        TraceALine(&p[start], length - start, width, out);
        fprintf(out, "\n");
    }
}

#define TCMALLOC(buf, len) buf = malloc(len)
#define next_char(c) \
    do { if( fread(&c, sizeof(char), 1, in) != 1 ) return; } while(0)

void hex_encode(FILE * in, FILE * out) {
    while(!feof(in)) {
        char c;
        next_char(c);
        fprintf(out, "%02X ", (unsigned char)c);
    }
}

void hex_decode(FILE * in, FILE * out) {
    int pos = 0;
    while(!feof(in)) {
        char c, r;
        next_char(c);
        pos++;
        if(c >= '0' && c <= '9'){
            r = c - '0';
        } else if(c >= 'a' && c <= 'f'){
            r = c - 'a' + 10;
        } else if(c >= 'A' && c <= 'F'){
            r = c - 'A' + 10;
        } else if(c == ' ' || c == '\t' || c == '\r' || c == '\n' ){
            continue;
        } else {
            fprintf(stderr, "format error at pos %d\n", pos);
            break;
        }
        next_char(c);
        pos++;
        if(c >= '0' && c <= '9'){
            r = r * 0x10 + c - '0';
        } else if(c >= 'a' && c <= 'f'){
            r = r * 0x10 + c - 'a' + 10;
        } else if(c >= 'A' && c <= 'F'){
            r = r * 0x10 + c - 'A' + 10;
        } else {
            fprintf(stderr, "format error at pos %d\n", pos);
            break;
        }
        fwrite(&r, sizeof(char), 1, out);
    }
}

#ifdef _TEST
void Usage(const char * prog)
{
    printf("%s [-d] [-f [-w width]]\n", prog);
    printf("  -d  decode\n");
    printf("  -f  code with format\n");
    printf("  -w  line width\n");
    exit(0);
}

int main(int argc, char * argv[]) {
    int i = 0;
    int decode = 0;
    int width = 16;
    int format = 0;
    for (i = 1;  i < argc; i++) {
        if(strcmp(argv[i], "-d") == 0 ) {
            decode = 1;
        } else if(strcmp(argv[i], "-f") == 0 ) {
            format = 1;
        } else if ( strcmp(argv[i], "-w") == 0 ) {
            if( i++ != argc ) {
                width = atoi(argv[i]);
            } else {
                Usage(argv[0]);
            }
        } else {
            Usage(argv[0]);
        }
    }
    if (decode == 0) {
        if (format == 1) {
            TraceMsg(width, stdin, stdout);
        } else {
            hex_encode(stdin, stdout);
        }
    } else {
        hex_decode(stdin, stdout);
    }
    return 0;
}
#endif
